# @Time : 2021/4/8 17:57
# @Author : Fioman 
# @Phone : 13149920693
import threading

import gevent

import settings
from eap_control.data_model import EmergencyMode, DeviceStatus, AlarmType
from eap_control.eap_config import EapConfig
from eap_control.eap_request import request_alarm_report
from eap_control.response_parse import parse_alarm_report_response
from tools.config_params import ConfigParams
from tools.hd_logger import HdLogger
from tools.send_to_ui_tools import *

"""
设备状态监控,每个设备创建一个线程,用来控制设备的状态,检测到设备状态以后要做的事情.
"""
cp = ConfigParams()
ec = EapConfig()


class StatesListener(object):
    def __init__(self, leftCam, middleCam, rightCam, cutterCam1, cutterCam2, cutterCam3, cutterCam4, camZmc, cbjZmc,
                 BigCutterZmc, SmallCutterZmc, deviceStates):
        self.db = DbHandler()
        self.logger = HdLogger()
        self.states = deviceStates
        self.camZmc = camZmc
        self.cbjZmc = cbjZmc
        self.bigCutterZmc = BigCutterZmc
        self.smallCutterZmc = SmallCutterZmc
        self.leftCam = leftCam
        self.middleCam = middleCam
        self.rightCam = rightCam
        self.cutterCam1 = cutterCam1
        self.cutterCam2 = cutterCam2
        self.cutterCam3 = cutterCam3
        self.cutterCam4 = cutterCam4
        self.loopDuration = 0.5
        self.managerThread = threading.Thread(target=self.manager,
                                              daemon=True, name="managerThread")
        self.camZmcListenerThread = threading.Thread(target=self.cam_zmc_listener,
                                                     daemon=True, name="camZmcListenerThread")
        self.cbjZmcListenerThread = threading.Thread(target=self.cbj_zmc_listener,
                                                     daemon=True, name="cbjZmcListenerThread")
        self.bigCutterZmcListenerThread = threading.Thread(target=self.big_cutter_zmc_listener,
                                                           daemon=True, name="bigCutterZmcListenerThread")
        self.smallCutterZmcListenerThread = threading.Thread(target=self.small_cutter_zmc_listener,
                                                             daemon=True, name="smallCutterZmcListenerThread")
        self.cameraGroupListenerThread = threading.Thread(target=self.camera_group_listener,
                                                          daemon=True, name="cameraGroupListenerThread")
        self.totalNotRunTimes = 0

    def cam_zmc_listener(self):
        """
        上料控制器的监听线程类
        :return:
        """
        while settings.IS_MAIN_ALIVE:

            connectState = self.camZmc.check_connect()
            if connectState:
                val = self.camZmc.get_opera_procedure_start()
                self.states.operaProcedureStart = True if val == 0 else False
                settings.MANIPULATOR_DIRECTION = self.states.operaProcedureStart
                valIO1 = [self.camZmc.get_io(bitNum)[1] for bitNum in range(0, 16)]
                valIO2 = [self.camZmc.get_io(bitNum)[1] for bitNum in range(24, 27)]
                valIO3 = [self.camZmc.get_io(bitNum)[1] for bitNum in range(54, 63)]
                valIOStart1 = self.get_Io_start_by_IO_val(valIO1, "camZmcIOInfo", 1)
                valIOStart2 = self.get_Io_start_by_IO_val(valIO2, "camZmcIOInfo", 2)
                valIOStart3 = self.get_Io_start_by_IO_val(valIO3, "camZmcIOInfo", 3)
                valIOStart = valIOStart1 + valIOStart2 + valIOStart3
                self.states.camZmcIOStates = valIOStart
                valOP1 = [self.camZmc.get_output(bitNum)[1] for bitNum in range(0, 5)]
                valOP2 = [self.camZmc.get_output(bitNum)[1] for bitNum in range(6, 7)]
                valOP3 = [self.camZmc.get_output(bitNum)[1] for bitNum in range(14, 15)]
                valOPstart1 = self.get_OP_start_by_Op_val(valOP1, "camZmcOPInfo", 1)
                valOPstart2 = self.get_OP_start_by_Op_val(valOP2, "camZmcOPInfo", 2)
                valOPstart3 = self.get_OP_start_by_Op_val(valOP3, "camZmcOPInfo", 3)
                valOPStart = valOPstart1 + valOPstart2 + valOPstart3
                self.states.camZmcOPStates = valOPStart
                # 检测设备是否是急停状态
                ret, val = self.camZmc.is_rs_stop()
                if ret == 0:
                    if val == 1:
                        self.states.camZmcStates.rs = True
                        if not self.states.camZmcIsRs:
                            self.states.camZmcIsRs = True  # 进入急停状态,不会再重复执行此段代码
                            self.logger.debug("检测到上料急停")
                            response = request_alarm_report(AlarmType.S,1)
                            parse_alarm_report_response(response)
                    else:
                        self.states.camZmcStates.rs = False
                        if self.states.camZmcIsRs:
                            self.states.camZmcIsRs = False
                            self.logger.debug("检测到上料急停状态去除!")
                            # 上料急停状态去除的 时候,把那个存放切线的队列清空.
                            # 想一下再不改变原来的操作逻辑的基础上怎么去修改这个东西.
                            # 通过前端作为媒介,搞一下,也是可以的.发送一个消息,给前端,前端收到之后再给后端发送清空切线队列的信号
                            msgVal = {
                                "val": "camZmcRsClearLineQueue",
                            }
                            send_produce_state_to_ui(msgVal)
                            response = request_alarm_report(AlarmType.R, 1)
                            parse_alarm_report_response(response)

                ret, val = self.camZmc.is_running()
                if ret == 0:
                    if val == 1:
                        self.states.camZmcStates.run = True
                        if not self.states.camZmcIsRun:
                            self.states.camZmcIsRun = True
                            ec.camZmcIsRunning = True
                            self.logger.debug("检测到上料进入运行状态")
                    else:
                        self.states.camZmcStates.run = False
                        if self.states.camZmcIsRun:
                            self.states.camZmcIsRun = False
                            self.logger.debug("检测到上料进入停止状态")
                            ec.camZmcIsRunning = False
            else:
                connectRes = self.camZmc.reconnect_cam_zmc()
                if connectRes == "ok":
                    self.states.camZmcStates.online = True
                    self.states.camZmcStates.rs = False
                    self.states.camZmcStates.run = False
                else:
                    self.states.camZmcStates.online = False
                    self.states.camZmcStates.rs = False
                    self.states.camZmcStates.run = False
                gevent.sleep(self.loopDuration)

            gevent.sleep(self.loopDuration)

    def cbj_zmc_listener(self):
        """
        裁切机控制器的监听线程类
        :return:
        """
        while settings.IS_MAIN_ALIVE:

            connectState = self.cbjZmc.check_connect()
            if connectState:
                valIO1 = [self.cbjZmc.get_io(bitNum)[1] for bitNum in range(0, 15)]
                valIO2 = [self.cbjZmc.get_io(bitNum)[1] for bitNum in range(24, 28)]
                valIOStart1 = self.get_Io_start_by_IO_val(valIO1, "cbjZmcIOInfo", 1)
                valIOStart2 = self.get_Io_start_by_IO_val(valIO2, "cbjZmcIOInfo", 2)
                valIOStart = valIOStart1 + valIOStart2
                self.states.cbjZmcIOStates = valIOStart

                valOP1 = [self.cbjZmc.get_output(bitNum)[1] for bitNum in range(0, 3)]
                valOP2 = [self.cbjZmc.get_output(bitNum)[1] for bitNum in range(8, 11)]
                valOP3 = [self.cbjZmc.get_output(bitNum)[1] for bitNum in range(12, 16)]
                valOPstart1 = self.get_OP_start_by_Op_val(valOP1, "cbjZmcOPInfo", 1)
                valOPstart2 = self.get_OP_start_by_Op_val(valOP2, "cbjZmcOPInfo", 2)
                valOPstart3 = self.get_OP_start_by_Op_val(valOP3, "cbjZmcOPInfo", 3)
                valOPStart = valOPstart1 + valOPstart2 + valOPstart3
                self.states.cbjZmcOPStates = valOPStart
                # 检测设备是否是急停状态
                ret, val = self.cbjZmc.is_rs_stop()
                if ret == 0:
                    if val == 1:
                        self.states.cbjZmcStates.rs = True
                        if not self.states.cbjZmcIsRs:
                            self.states.cbjZmcIsRs = True  # 进入急停状态,不会再重复执行此段代码
                            self.logger.debug("检测到裁切机急停")
                            ec.realStatusData.emergencyMode = EmergencyMode.Emergency
                            ec.realStatusData.statusId = DeviceStatus.Stop.name
                            ec.realStatusData.alarmId = "2"
                            response = request_alarm_report(AlarmType.S, 2)
                            parse_alarm_report_response(response)
                    else:
                        self.states.cbjZmcStates.rs = False
                        if self.states.cbjZmcIsRs:
                            self.logger.debug("裁切机急停状态去除!")
                            self.states.cbjZmcIsRs = False
                            ec.realStatusData.alarmId = ""
                            ec.realStatusData.emergencyMode = EmergencyMode.Normal
                            ec.realStatusData.statusId = DeviceStatus.Stop.name
                            response = request_alarm_report(AlarmType.R, 2)
                            parse_alarm_report_response(response)

                ret, val = self.cbjZmc.is_running()
                if ret == 0:
                    if val == 1:
                        self.states.cbjZmcStates.run = True
                        if not self.states.cbjZmcIsRun:
                            self.states.cbjZmcIsRun = True
                            self.logger.debug("检测到裁切机进入运行状态")
                            ec.realStatusData.alarmId = ""
                            ec.realStatusData.emergencyMode = EmergencyMode.Normal
                            ec.cbjZmcIsRunning = True
                    else:
                        self.states.cbjZmcStates.run = False
                        if self.states.cbjZmcIsRun:
                            self.states.cbjZmcIsRun = False
                            self.logger.debug("检测到裁切机进入停止状态")
                            ec.realStatusData.alarmId = ""
                            ec.realStatusData.emergencyMode = EmergencyMode.Normal
                            ec.realStatusData.statusId = DeviceStatus.Stop.name
                            ec.cbjZmcIsRunning = False
            else:
                connectRes = self.cbjZmc.reconnect_cbj_zmc()
                if connectRes == "ok":
                    self.states.cbjZmcStates.online = True
                    self.states.cbjZmcStates.rs = False
                    self.states.cbjZmcStates.run = False
                else:
                    self.states.cbjZmcStates.online = False
                    self.states.cbjZmcStates.rs = False
                    self.states.cbjZmcStates.run = False

            gevent.sleep(self.loopDuration)

    def big_cutter_zmc_listener(self):
        """
        大铡刀控制器的监听线程类
        :return:
        """
        while settings.IS_MAIN_ALIVE:
            connectState = self.bigCutterZmc.check_connect()
            if connectState:
                valIO1 = [self.bigCutterZmc.get_io(bitNum)[1] for bitNum in range(0, 19)]
                valIO2 = [self.bigCutterZmc.get_io(bitNum)[1] for bitNum in range(20, 24)]
                valIO3 = [self.bigCutterZmc.get_io(bitNum)[1] for bitNum in range(40, 45)]
                valIOStart1 = self.get_Io_start_by_IO_val(valIO1, "bigCutterIOInfo", 1)
                valIOStart2 = self.get_Io_start_by_IO_val(valIO2, "bigCutterIOInfo", 2)
                valIOStart3 = self.get_Io_start_by_IO_val(valIO3, "bigCutterIOInfo", 3)
                valIOStart = valIOStart1 + valIOStart2 + valIOStart3
                self.states.bigCutterZmcIOInfo = valIOStart

                valOP1 = [self.bigCutterZmc.get_output(bitNum)[1] for bitNum in range(0, 26)]
                valOPstart1 = self.get_OP_start_by_Op_val(valOP1, "bigCutterOPInfo", 1)
                valOPStart = valOPstart1
                self.states.bigCutterZmcOPStates = valOPStart
                # 检测所有的报警信息
                val = [self.bigCutterZmc.get_modbus_bit(bitNum, 1)[1][0] for bitNum in range(3000, 3200)]
                alarmInfo = self.get_main_alarm_info_by_bit_val(val)
                self.states.mainAlarmInfo = alarmInfo
                self.states.mainAlarmInfoVisible = True if alarmInfo != "" and alarmInfo != "\n" else False
                ret, val = self.bigCutterZmc.is_rs_stop()
                if ret == 0:
                    if val == 1:
                        self.states.bigCutterZmcStates.rs = True
                        if not self.states.bigCutterZmcIsRs:
                            self.states.bigCutterZmcIsRs = True
                            self.logger.debug("检测到大铡刀控制器进入到急停状态")
                            ec.realStatusData.emergencyMode = EmergencyMode.Emergency
                            ec.realStatusData.statusId = DeviceStatus.Down.name
                            ec.realStatusData.alarmId = "3"
                            response = request_alarm_report(AlarmType.S, 3)
                            parse_alarm_report_response(response)
                    else:
                        self.states.bigCutterZmcStates.rs = False
                        if self.states.bigCutterZmcIsRs:
                            self.states.bigCutterZmcIsRs = False
                            self.logger.debug("检测到大铡刀控制器急停状态去除!")
                            ec.realStatusData.alarmId = ""
                            ec.realStatusData.emergencyMode = EmergencyMode.Normal
                            ec.realStatusData.statusId = DeviceStatus.Initial.name
                            response = request_alarm_report(AlarmType.R, 3)
                            parse_alarm_report_response(response)

                ret, val = self.bigCutterZmc.is_running()
                if ret == 0:
                    if val == 1:
                        self.states.bigCutterZmcStates.run = True
                        if not self.states.bigCutterZmcIsRun:
                            self.states.bigCutterZmcIsRun = True
                            self.logger.debug("检测到大铡刀进入运行状态")
                            ec.realStatusData.alarmId = ""
                            ec.realStatusData.emergencyMode = EmergencyMode.Normal
                            ec.bigCutterZmcIsRunning = True
                    else:
                        self.states.bigCutterZmcStates.run = False
                        if self.states.bigCutterZmcIsRun:
                            self.states.bigCutterZmcIsRun = False
                            ec.realStatusData.alarmId = ""
                            ec.realStatusData.emergencyMode = EmergencyMode.Normal
                            ec.realStatusData.statusId = DeviceStatus.Stop.name
                            ec.bigCutterZmcIsRunning = False
                            self.logger.debug("检测到大铡刀进入停止状态")
            else:
                connectRes = self.bigCutterZmc.reconnect_cutter_zmc()
                if connectRes == "ok":
                    self.states.bigCutterZmcStates.online = True
                    self.states.bigCutterZmcStates.rs = False
                    self.states.bigCutterZmcStates.run = False
                else:
                    self.states.bigCutterZmcStates.online = False
                    self.states.bigCutterZmcStates.rs = False
                    self.states.bigCutterZmcStates.run = False
            gevent.sleep(self.loopDuration)

    def small_cutter_zmc_listener(self):
        """
        小铡刀控制器的监听线程类
        :return:
        """
        while settings.IS_MAIN_ALIVE:
            connectState = self.smallCutterZmc.check_connect()
            if connectState:
                valIO1 = [self.smallCutterZmc.get_io(bitNum)[1] for bitNum in range(0, 24)]
                valIO2 = [self.smallCutterZmc.get_io(bitNum)[1] for bitNum in range(40, 46)]
                valIOStart1 = self.get_Io_start_by_IO_val(valIO1, "smallCutterIOInfo", 1)
                valIOStart2 = self.get_Io_start_by_IO_val(valIO2, "smallCutterIOInfo", 2)
                valIOStart = valIOStart1 + valIOStart2
                self.states.smallCutterZmcIOInfo = valIOStart

                valOP1 = [self.smallCutterZmc.get_output(bitNum)[1] for bitNum in range(0, 28)]
                valOPstart1 = self.get_OP_start_by_Op_val(valOP1, "smallCutterOPInfo", 1)
                valOPStart = valOPstart1
                self.states.smallCutterZmcOPStates = valOPStart

                ret, val = self.smallCutterZmc.is_rs_stop()
                if ret == 0:
                    if val == 1:
                        self.states.smallCutterZmcStates.rs = True
                        if not self.states.smallCutterZmcIsRs:
                            self.states.smallCutterZmcIsRs = True
                            self.logger.debug("检测到小铡刀控制器进入到急停状态")
                            ec.realStatusData.emergencyMode = EmergencyMode.Emergency
                            ec.realStatusData.statusId = DeviceStatus.Down.name
                            ec.realStatusData.alarmId = "4"
                            response = request_alarm_report(AlarmType.S, 4)
                            parse_alarm_report_response(response)
                    else:
                        self.states.smallCutterZmcStates.rs = False
                        if self.states.smallCutterZmcIsRs:
                            self.states.smallCutterZmcIsRs = False
                            self.logger.debug("检测到小铡刀控制器急停状态去除!")
                            ec.realStatusData.alarmId = ""
                            ec.realStatusData.emergencyMode = EmergencyMode.Normal
                            ec.realStatusData.statusId = DeviceStatus.Initial.name
                            response = request_alarm_report(AlarmType.R, 4)
                            parse_alarm_report_response(response)

                ret, val = self.smallCutterZmc.is_running()
                if ret == 0:
                    if val == 1:
                        self.states.smallCutterZmcStates.run = True
                        if not self.states.smallCutterZmcIsRun:
                            self.states.smallCutterZmcIsRun = True
                            self.logger.debug("检测到小铡刀进入运行状态")
                            ec.smallCutterZmcIsRunning = True
                            ec.realStatusData.alarmId = ""
                            ec.realStatusData.emergencyMode = EmergencyMode.Normal
                    else:
                        self.states.smallCutterZmcStates.run = False
                        if self.states.smallCutterZmcIsRun:
                            self.states.smallCutterZmcIsRun = False
                            self.logger.debug("检测到小铡刀进入停止状态")
                            ec.smallCutterZmcIsRunning = False
                            ec.realStatusData.alarmId = ""
                            ec.realStatusData.emergencyMode = EmergencyMode.Normal
                            ec.realStatusData.statusId = DeviceStatus.Stop.name
            else:
                connectRes = self.smallCutterZmc.reconnect_cutter_zmc()
                if connectRes == "ok":
                    self.states.smallCutterZmcStates.online = True
                    self.states.smallCutterZmcStates.rs = False
                    self.states.smallCutterZmcStates.run = False
                else:
                    self.states.smallCutterZmcStates.online = False
                    self.states.smallCutterZmcStates.rs = False
                    self.states.smallCutterZmcStates.run = False
            gevent.sleep(self.loopDuration)

    def get_OP_start_by_Op_val(self, val, table, frequency):
        """
                根据底层的bit位信息,获取报警信息,如果没有报警信息,就返回空串,或者出错,也返回空串
                :param val:
                :return:
                """
        try:
            IOInfoAlarm = []
            # 获取报警信息的内容
            res, alarmData = self.db.get_IO_info(table)
            if res != "ok":
                errorInfo = "in get_OP_start_by_Op_val() error: get_main_alarm_info数据错误,数据库异常"
                print(errorInfo)
                self.logger.debug(errorInfo)
            for i in range(len(val)):
                IOInfo = {}

                if val[i] == 1:
                    IOInfo["start"] = "{}".format("On")
                else:
                    IOInfo["start"] = "{}".format("Off")
                if table == "camZmcOPInfo":
                    if frequency == 2:
                        i = i + 6
                    elif frequency == 3:
                        i = i + 14
                elif table == "cbjZmcOPInfo":
                    if frequency == 2:
                        i = i + 8
                    elif frequency == 3:
                        i = i + 12
                IOInfo["key"] = "{}".format(i)
                IOInfo["OP"] = "Op{}".format(i)
                IOInfo["annotation"] = "{}".format(alarmData["{}".format(i)])
                IOInfoAlarm.append(IOInfo)
            return IOInfoAlarm
        except Exception as e:
            errorInfo = "in get_OP_start_by_Op_val: error:{}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

    def get_Io_start_by_IO_val(self, val, table, frequency):
        """
        根据底层的bit位信息,获取报警信息,如果没有报警信息,就返回空串,或者出错,也返回空串
        :param val:
        :return:
        """
        try:
            IOInfoAlarm = []
            # 获取报警信息的内容
            res, alarmData = self.db.get_IO_info(table)
            if res != "ok":
                errorInfo = "in get_Io_start_by_IO_val() error: get_main_alarm_info数据错误,数据库异常"
                print(errorInfo)
                self.logger.debug(errorInfo)
            for i in range(len(val)):
                IOInfo = {}
                IOInfo["I/O"] = "{}".format(i)
                if val[i] == 1:
                    IOInfo["start"] = "{}".format("On")
                else:
                    IOInfo["start"] = "{}".format("Off")
                if table == "camZmcIOInfo":
                    if frequency == 2:
                        i = i + 24
                    elif frequency == 3:
                        i = i + 54
                elif table == "cbjZmcIOInfo":
                    if frequency == 2:
                        i = i + 24
                elif table == "bigCutterIOInfo":
                    if frequency == 2:
                        i = i + 20
                    elif frequency == 3:
                        i = i + 40
                elif table == "smallCutterIOInfo":
                    if frequency == 2:
                        i = i + 40
                IOInfo["In"] = "in{}".format(i)
                IOInfo["annotation"] = "{}".format(alarmData["{}".format(i)])
                IOInfoAlarm.append(IOInfo)
            return IOInfoAlarm
        except Exception as e:
            errorInfo = "in get_alarm_info_by_bit_val: error:{}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

    def get_main_alarm_info_by_bit_val(self, val):
        """
        根据底层的bit位信息,获取报警信息,如果没有报警信息,就返回空串,或者出错,也返回空串
        :param val:
        :return:
        """
        try:
            alarmVal = [3000 + index for index, bitVal in enumerate(val) if bitVal != 0]
            # 获取报警信息的内容
            # if cp.language == '简体中文':
            res, alarmData = self.db.get_main_alarm_info()
            # else:
            res, alarmDataUS = self.db.get_main_alarm_info_US()
            if res != "ok":
                errorInfo = "in get_alarm_info_by_bit_val() error: get_main_alarm_info数据错误,数据库异常"
                print(errorInfo)
                self.logger.debug(errorInfo)
            else:
                infoDict = alarmData.get("mainAlarmInfo")
                alarmInfo = ""
                for alarmBit in alarmVal:
                    info = infoDict.get(str(alarmBit), "")
                    if info != "":
                        if alarmInfo != "":
                            alarmInfo = alarmInfo + ", " + info
                        else:
                            alarmInfo = info
                infoDictUS = alarmDataUS.get("mainAlarmInfo")
                alarmInfoUS = ""
                for alarmBit in alarmVal:
                    info = infoDictUS.get(str(alarmBit), "")
                    if info != "":
                        if alarmInfoUS != "":
                            alarmInfoUS = alarmInfoUS + ", " + info
                        else:
                            alarmInfoUS = info
                alarmInfo = alarmInfoUS + "\n" + alarmInfo
                return alarmInfo
        except Exception as e:
            errorInfo = "in get_alarm_info_by_bit_val: error:{}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

    def camera_group_listener(self):
        """
        相机组的监听线程类
        :return:
        """
        leftCamConnected = True
        middleCamConnected = True
        rightCamConnected = True
        cutterCam1Connected = True
        cutterCam2Connected = True
        cutterCam3Connected = True
        cutterCam4Connected = True
        while settings.IS_MAIN_ALIVE:
            leftCamIsOnline = self.leftCam.is_device_online()
            middleCamIsOnline = self.middleCam.is_device_online()
            rightCamIsOnline = self.rightCam.is_device_online()
            cutterCam1IsOnline = self.cutterCam1.is_device_online()
            cutterCam2IsOnline = self.cutterCam2.is_device_online()
            cutterCam3IsOnline = self.cutterCam3.is_device_online()
            cutterCam4IsOnline = self.cutterCam4.is_device_online()
            self.states.cameraGroupStates = [leftCamIsOnline, middleCamIsOnline, rightCamIsOnline, cutterCam1IsOnline, cutterCam2IsOnline, cutterCam3IsOnline, cutterCam4IsOnline]
            if not leftCamIsOnline:
                ret = self.reconnect_left_cam()
                if ret != 0:
                    if leftCamConnected:
                        self.logger.debug(ret)
                    leftCamConnected = False
                else:
                    leftCamIsOnline = True
                    leftCamConnected = True
                    self.logger.debug("上料左相机连接成功!")

            if not middleCamIsOnline:
                ret = self.reconnect_middle_cam()
                if ret != 0:
                    if middleCamConnected:
                        self.logger.debug(ret)
                    middleCamConnected = False
                else:
                    middleCamIsOnline = True
                    middleCamConnected = True
                    self.logger.debug("上料中间相机连接成功!")

            if not rightCamIsOnline:
                ret = self.reconnect_right_cam()
                if ret != 0:
                    if rightCamConnected:
                        self.logger.debug(ret)
                    rightCamConnected = False
                else:
                    rightCamIsOnline = True
                    rightCamConnected = True
                    self.logger.debug("上料右相机连接成功!")

            if not cutterCam1IsOnline:
                ret = self.reconnect_cutter_cam1()
                if ret != 0:
                    if cutterCam1Connected:
                        self.logger.debug(ret)
                    cutterCam1Connected = False
                else:
                    cutterCam1IsOnline = True
                    cutterCam1Connected = True
                    self.logger.debug("铡刀1号相机连接成功!")

            if not cutterCam2IsOnline:
                ret = self.reconnect_cutter_cam2()
                if ret != 0:
                    if cutterCam2Connected:
                        self.logger.debug(ret)
                    cutterCam2Connected = False
                else:
                    cutterCam2IsOnline = True
                    cutterCam2Connected = True
                    self.logger.debug("铡刀2号相机连接成功!")
            if not cutterCam3IsOnline:
                ret = self.reconnect_cutter_cam3()
                if ret != 0:
                    if cutterCam3Connected:
                        self.logger.debug(ret)
                    cutterCam3Connected = False
                else:
                    cutterCam3IsOnline = True
                    cutterCam3Connected = True
                    self.logger.debug("铡刀3号相机连接成功!")
            if not cutterCam4IsOnline:
                ret = self.reconnect_cutter_cam4()
                if ret != 0:
                    if cutterCam4Connected:
                        self.logger.debug(ret)
                    cutterCam4Connected = False
                else:
                    cutterCam4IsOnline = True
                    cutterCam4Connected = True
                    self.logger.debug("铡刀4号相机连接成功!")

            self.states.cameraGroupStates = [leftCamIsOnline, middleCamIsOnline, rightCamIsOnline, cutterCam1IsOnline, cutterCam2IsOnline, cutterCam3IsOnline, cutterCam4IsOnline]
            gevent.sleep(self.loopDuration)

    def manager(self):
        """
        线程管理类
        :return:
        """
        self.updateStatesFlag = False
        while settings.IS_MAIN_ALIVE:
            # 检测Eap状态是否发生了变化,如果发生变化,要去呼叫Eap
            if not self.states.camZmcStates.run and not self.states.cbjZmcStates.run and not self.states.bigCutterZmcStates.run and not self.states.smallCutterZmcStates.run:
                # 有这种可能,设备在上电的一瞬间,它之前已经检测到设备的状态是非运行状态,但是这个时候设备刚刚启动完成,然后这里的状态没有实时的去更新,
                # 就会造成检测的状态失效,这里该如何去搞定这件事呢,就是每次如果检测到不是运行状态,就把非运行状态的计数设置为1,如果超过了三次,就认为确实是不是运行状态即可
                self.totalNotRunTimes += 1
                if self.totalNotRunTimes > 2:  # 这个状态检测到两次以上再判定自动作业退出
                    self.states.workStopFlag = True
                    self.totalNotRunTimes = 0

                # 先去获取数据库中的中实践
                cp.totalRunTimes += 1.1 # 总时间加 1秒
                newData = {
                    "totalRunTimes": cp.totalRunTimes,
                }
                if ec.realStatusData.statusId ==  DeviceStatus.Run.name:
                    cp.useTimes += 1.1   # 使用时间加1秒
                    newData["useTimes"] = cp.useTimes
                ec.totalRunTime = round(ec.totalRunTime  / 60 / 60 ,3)
                ec.usePercent = round(cp.useTimes / cp.totalRunTimes,2)
                db.save_config_params(newData)
            else:
                self.totalNotRunTimes = 0
            # 实时更新设备状态
            self.send_device_state_to_ui()
            # 将设备状态写入到数据库,好发送给eap
            self.write_device_state_to_mogodb()
            try:
                if not self.camZmcListenerThread.is_alive():
                    self.camZmcListenerThread = threading.Thread(target=self.cam_zmc_listener, name="camZmcListenerThread")
                    self.camZmcListenerThread.setDaemon(True)
                    self.camZmcListenerThread.start()

                if not self.cbjZmcListenerThread.is_alive():
                    self.cbjZmcListenerThread = threading.Thread(target=self.cbj_zmc_listener, name="cbjZmcListenerThread")
                    self.cbjZmcListenerThread.setDaemon(True)
                    self.cbjZmcListenerThread.start()

                if not self.bigCutterZmcListenerThread.is_alive():
                    self.bigCutterZmcListenerThread = threading.Thread(target=self.big_cutter_zmc_listener, name="bigCutterZmcListenerThread")
                    self.bigCutterZmcListenerThread.setDaemon(True)
                    self.bigCutterZmcListenerThread.start()

                if not self.smallCutterZmcListenerThread.is_alive():
                    self.smallCutterZmcListenerThread = threading.Thread(target=self.small_cutter_zmc_listener, name="smallCutterZmcListenerThread")
                    self.smallCutterZmcListenerThread.setDaemon(True)
                    self.smallCutterZmcListenerThread.start()

                if not self.cameraGroupListenerThread.is_alive():
                    self.cameraGroupListenerThread = threading.Thread(target=self.camera_group_listener, name="cameraGroupListenerThread")
                    self.cameraGroupListenerThread.setDaemon(True)
                    self.cameraGroupListenerThread.start()

                if not self.updateStatesFlag:
                    loginSuccess = self.db.get_login_state()
                    if loginSuccess:
                        gevent.sleep(0.3)
                        self.web_show_data_initial()
                        self.db.update_login_state(False)
                        self.updateStatesFlag = True
                    else:
                        msgVal = {
                            "usernames": self.db.get_usernames()[1]
                        }
                        send_login_usernames_to_ui(msgVal)
            except Exception as e:
                errorInfo = "in manager() error: {}".format(str(e))
                print(errorInfo)
                self.logger.debug(errorInfo)
                gevent.sleep(1)

            gevent.sleep(1)

    def web_show_data_initial(self):
        """
        前端界面的一些显示数据的初始化
        :return:
        """
        orderUsedKey = self.db.get_working_used_key()
        msg = {
            "val": orderUsedKey
        }
        send_order_state_to_ui(msg)
        # 更新workingInfo的数据
        send_working_info_state_to_ui()
        # 更新设置界面的参数
        send_settings_update_to_ui()
        # 更新裁切机控制器工具中的界面的参数
        msgValue = {
            "val": "updateKnifeCutParams",
        }
        send_cbj_zmc_tool_state_to_ui(msgValue)
        # 更新相机拼接参数到相机拼接的界面
        msgValue = {
            "val": "updateJointParams",
        }
        send_line_camera_joint_state(msgValue)
        # 更新铡刀标定的时候的参数信息到界面
        msgValue = {
            "val": "updateLightParamsBig",
        }
        send_big_cutter_camera_cal_state(msgValue)
        msgValue = {
            "val": "updateLightParamsSmall",
        }
        send_small_cutter_camera_cal_state(msgValue)
        # msgValue = {
        #     "val": "updateEapParamsState",
        # }
        # send_eap_msg_state_to_ui(msgValue)
        # 去请求are_you_there_reqeust
        # response = eap_request.request_are_you_there()
        # result, _, _ = eap_request.parse_are_you_there_response(response)
        # if result.lower() == "ok":
        #     ec.eap_is_online = True
        # else:
        #     ec.eap_is_online = False
        # update_eap_status(ec.eap_is_online)
        # update_current_user_id(ec.user_id)
        #  将eap界面模块的初始化信息,更新到UI
        ec.send_init_data_to_ui()

    def send_device_state_to_ui(self):
        """
        将device的状态信息发送给前端,就是状态类监控到的设备信息
        :return:
        """
        msgType = "deviceStates"
        msg = self.states.pack_state_to_dict()
        send_msg_to_ui(msgType, msg)

    def write_device_state_to_mogodb(self):
        """
        将设备的状态写入到数据库中
        :return:
        """
        camZmcRsVal = "0"  # 默认是0,如果有急停,就更改它的值
        cbjZmcRsVal = "0"  # 默认是0,如果有急停,就更改它的值
        bigCutterZmcRsVal = "0"  # 默认是0,如果有急停,就更改它的值
        smallCutterZmcRsVal = "0"  # 默认是0,如果有急停,就更改它的值

        if self.states.camZmcStates.rs:
            camZmcStatesVal = "2"
            camZmcRsVal = "上料控制器急停"
        elif self.states.camZmcStates.run:
            camZmcStatesVal = "1"
        else:
            camZmcStatesVal = "0"

        if self.states.cbjZmcStates.rs:
            cbjZmcStatesVal = "2"
            cbjZmcRsVal = "裁切机控制器急停"
        elif self.states.cbjZmcStates.run:
            cbjZmcStatesVal = "1"
        else:
            cbjZmcStatesVal = "0"

        if self.states.bigCutterZmcStates.rs:
            bigCutterZmcStatesVal = "2"
            bigCutterZmcRsVal = "大铡刀控制器急停"
        elif self.states.bigCutterZmcStates.run:
            bigCutterZmcStatesVal = "1"
        else:
            bigCutterZmcStatesVal = "0"

        if self.states.smallCutterZmcStates.rs:
            smallCutterZmcStatesVal = "2"
            smallCutterZmcRsVal = "小铡刀控制器急停"
        elif self.states.smallCutterZmcStates.run:
            smallCutterZmcStatesVal = "1"
        else:
            smallCutterZmcStatesVal = "0"

        query = {
            "key": "1"
        }
        newDeviceStatesVal = {
            "$set": {
                "camZmcStates": camZmcStatesVal,
                "cbjZmcStates": cbjZmcStatesVal,
                "bigCutterZmcStates": bigCutterZmcStatesVal,
                "smallCutterZmcStates": smallCutterZmcStatesVal
            }
        }
        self.db.update_data(self.db.deviceStateToEapTable, query, newDeviceStatesVal)

        newAlarmReportVal = {
            "$set": {
                "camZmcRs": camZmcRsVal,
                "cbjZmcRs": cbjZmcRsVal,
                "bigCutterZmcRs": bigCutterZmcRsVal,
                "smallCutterZmcRs": smallCutterZmcRsVal,
            }
        }
        self.db.update_data(self.db.alarmReportToEapTable, query, newAlarmReportVal)

    def reconnect_left_cam(self):
        """
        重新连接上料左相机
        :return: 成功返回0,失败返回失败原因
        """
        try:
            ret = self.leftCam.re_connect_line_camera()
            if ret != 0:
                self.leftCam.errorMsg = "上料左相机连接失败,原因:{}".format(ret)
                return self.leftCam.errorMsg
            else:
                self.leftCam.start_grabbing()  # 打开相机
                return 0
        except Exception as e:
            print("in reconnect_left_cam() error : {}".format(str(e)))
            return "上料左相机连接失败,失败原因:{}".format(str(e))

    def reconnect_middle_cam(self):
        """
        重新连接上料左相机
        :return: 成功返回0,失败返回失败原因
        """
        try:
            ret = self.middleCam.re_connect_line_camera()
            if ret != 0:
                self.middleCam.errorMsg = "上料中间相机连接失败,原因:{}".format(ret)
                return self.middleCam.errorMsg
            else:
                self.middleCam.start_grabbing()  # 打开相机
                return 0
        except Exception as e:
            print("in reconnect_middle_cam() error : {}".format(str(e)))
            return "上料中间相机连接失败,失败原因:{}".format(str(e))

    def reconnect_right_cam(self):
        """
        重新连接右相机
        :return: 成功返回0,失败返回失败原因
        """
        try:
            ret = self.rightCam.re_connect_line_camera()
            if ret != 0:
                self.rightCam.errorMsg = "上料右相机连接失败,原因:{}".format(ret)
                return self.rightCam.errorMsg
            else:
                self.rightCam.start_grabbing()  # 打开相机
                return 0
        except Exception as e:
            print("in reconnect_right_cam() error : {}".format(str(e)))
            return "上料右相机连接失败,失败原因:{}".format(str(e))

    def reconnect_cutter_cam1(self):
        """
        重新连接铡刀相机
        :return: 成功返回0 失败返回失败原因
        """
        try:
            ret = self.cutterCam1.re_connect_area_camera()
            if ret != 0:
                self.cutterCam1.errorMsg = "铡刀1号相机连接失败,原因:{}".format(ret)
                return self.cutterCam1.errorMsg
            else:
                return 0
        except Exception as e:
            print("in reconnect_cutter_cam1() error : {}".format(str(e)))
            return "铡刀1号相机连接失败,失败原因:{}".format(str(e))

    def reconnect_cutter_cam2(self):
        """
        重新连接铡刀2号相机
        :return: 成功返回0,失败返回失败原因
        """
        try:
            ret = self.cutterCam2.re_connect_area_camera()
            if ret != 0:
                self.cutterCam2.errorMsg = "铡刀2号相机连接失败,原因:{}".format(ret)
                return self.cutterCam2.errorMsg
            else:
                return 0
        except Exception as e:
            print("in reconnect_cutter_cam2() error : {}".format(str(e)))
            return "铡刀2号相机连接失败,失败原因:{}".format(str(e))

    def reconnect_cutter_cam3(self):
        """
        重新连接铡刀3号相机
        :return: 成功返回0,失败返回失败原因
        """
        try:
            ret = self.cutterCam3.re_connect_area_camera()
            if ret != 0:
                self.cutterCam3.errorMsg = "铡刀3号相机连接失败,原因:{}".format(ret)
                return self.cutterCam3.errorMsg
            else:
                return 0
        except Exception as e:
            print("in reconnect_cutter_cam3() error : {}".format(str(e)))
            return "铡刀3号相机连接失败,失败原因:{}".format(str(e))

    def reconnect_cutter_cam4(self):
        """
        重新连接铡刀4号相机
        :return: 成功返回0,失败返回失败原因
        """
        try:
            ret = self.cutterCam4.re_connect_area_camera()
            if ret != 0:
                self.cutterCam4.errorMsg = "铡刀4号相机连接失败,原因:{}".format(ret)
                return self.cutterCam4.errorMsg
            else:
                return 0
        except Exception as e:
            print("in reconnect_cutter_cam4() error : {}".format(str(e)))
            return "铡刀4号相机连接失败,失败原因:{}".format(str(e))
